﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SCRUM.Core.BusinessObjects;
using SCRUM.Core.DAO;
using System.Data.Common;
using System.Data.SqlClient;
using SCRUM.Core.Exceptions.Database;

namespace SCRUM.Core.DataProviders
{
    /// <summary>
    /// Privider for comunication with the database for release
    /// </summary>
    public partial class DBDataProvider : DataProvider
    {
        /// <summary>
        /// Creates new release.
        /// </summary>
        /// <param name="release">The specific release.</param>
        /// <param name="projectId">Project to add release to.</param>
        /// <returns>Created Release with ID</returns>
        public override Release CreateRelease(Release release, int projectId)
        {
            int releaseID = InsertRelease(release, projectId);
            return GetReleaseById(releaseID);
        }

        /// <summary>
        /// Inserts the release into database.
        /// </summary>
        /// <param name="release">The release.</param>
        /// <param name="projectId">The project id.</param>
        /// <returns>identifier of a new release </returns>
        private int InsertRelease(Release release, int projectId)
        {
            try
            {
                DbParameter dbName = CreateParameter("name", release.Name);
                DbParameter dbVers = CreateParameter("version", release.Version);
                DbParameter dbProjectId = CreateParameter("projectId", projectId);
                DbParameter dbEst = CreateParameter("estimation", release.Estimation);

                connection.Open();

                int data = ExecuteNonQuery("release/CreateRelease", dbName, dbVers, dbProjectId, dbEst);
                if (data != 1)
                {
                    throw new InconsistentDatabaseException("ReleaseNotCreated");
                }
                return Convert.ToInt32(GetScalar("release/GetLastInsertedReleaseID")); 
            }
            finally
            {
                connection.Close();
            }
        }



        /// <summary>
        /// Updates the release.
        /// </summary>
        /// <param name="release">The specific release.</param>
        /// <param name="projectId">Id of project to add release to.</param>
        public override void UpdateRelease(Release release, int projectId) 
        {
            try
            {
                DbParameter dbId = CreateParameter("releaseId", release.ID);
                DbParameter dbName = CreateParameter("name", release.Name);
                DbParameter dbVers = CreateParameter("version", release.Version);
                DbParameter dbProjectId = CreateParameter("projectId", projectId);
                DbParameter dbEst = CreateParameter("estimation", release.Estimation);

                connection.Open();

                int data = ExecuteNonQuery("release/UpdateRelease", dbId, dbName, dbVers, dbProjectId, dbEst);
                if (data != 1)
                {
                    throw new InconsistentDatabaseException("ReleaseToBeUpdatedNotFound");
                }
            }
            catch (SqlException)
            {
                throw new InconsistentDatabaseException("ReleaseCouldNotBeUpdated");
            }
            finally
            {
                connection.Close();
            }
        }

        /// <summary>
        /// Deletes the release.
        /// </summary>
        /// <param name="releaseId">The specific release id.</param>
        public override void DeleteRelease(int releaseId)
        {
            try
            {
                DbParameter dbId = CreateParameter("releaseId", releaseId);

                connection.Open();
                int data = ExecuteNonQuery("release/DeleteRelease", dbId);
                if (data != 1)
                {
                    throw new Exception("ReleaseToBeDeletedNotFound");
                }
            }
            catch (SqlException)
            {
                throw new InconsistentDatabaseException("ReleaseCouldNotBeDeleted");
            }
            finally
            {
                connection.Close();
            }
        }

        /// <summary>
        /// Creates release from dataReader
        /// </summary>
        /// <param name="data">Result from database</param>
        /// <returns>Created release</returns>
        private Release GetRelease(DbDataReader data)
        {
            return new Release(
                GetIntByColumn(data, "ID")
                , GetStringByColumn(data, "NAME")
                , GetStringByColumn(data, "VERSION")
                , GetDoubleByColumn(data, "ESTIMATION")
                , GetDoubleByColumn(data, "PROGRESS")
                , GetIntByColumn(data, "PROJECT_ID")
                , GetDateByColumn(data, "CHANGED")
            );
        }

        /// <summary>
        /// Gets all releases.
        /// </summary>
        /// <param name="releaseID">The release ID.</param>
        /// <param name="projectID">The project ID.</param>
        /// <param name="sprintID">The sprint ID.</param>
        /// <returns></returns>
        public override IList<Release> GetAllReleases(int releaseID, int projectID, int sprintID)
        {
            try
            {
                IList<Release> releases = new List<Release>();

                DbParameter dbReleaseID = CreateParameter("releaseID", releaseID);
                DbParameter dbProjectID = CreateParameter("projectID", projectID);
                DbParameter dbSprintID = CreateParameter("sprintID", sprintID);

                connection.Open();
                DbDataReader data = GetGrid("release/GetAllReleases", dbReleaseID, dbProjectID, dbSprintID);

                while (data.Read())
                {
                    Release release = GetRelease(data);
                    releases.Add(release);
                }
                return releases;
            }
            finally
            {
                connection.Close();                
            }
        }

        /// <summary>
        /// Get all releases.
        /// </summary>
        public override IList<Release> GetAllReleases()
        {
            return GetAllReleases(-1, -1, -1);
        }

        /// <summary>
        ///  Returns release according to id
        /// </summary>
        /// <param name="releaseId">id of release</param>
        /// <returns>release details</returns>
        public override Release GetReleaseById(int releaseId)
        {
            IList<Release> releases = GetAllReleases(releaseId, -1, -1);
            if (releases.Count != 1)
            {
                throw new InconsistentDatabaseException("ReleaseNotFound");
            }
            return releases[0];
        }

        /// <summary>
        /// Gets the release by sprint.
        /// </summary>
        /// <param name="sprintID">The sprint.</param>
        /// <returns>release the sprint belongs to</returns>
        public override Release GetReleaseBySprintID(int sprintID)
        {
            IList<Release> releases = GetAllReleases(-1, -1, sprintID);
            if (releases.Count != 1)
            {
                throw new InconsistentDatabaseException("ReleaseNotFound");
            }
            return releases[0];
        }

        /// <summary>
        /// Get all releases for specific project.
        /// </summary>
        /// <param name="projectId">Id of project</param>
        public override IList<Release> GetAllReleasesForProject(int projectId)
        {
            return GetAllReleases(-1, projectId, -1);
        }
    }
}
